<template>
	<scroll-view class="c-list" :style='[listStyle]' scroll-y="true" :refresher-enabled='ableRefresh'
		refresher-threshold='40' :refresher-triggered='refreshTrigger' @refresherrefresh='onPullRefreshing'
		@scrolltolower='onLoadMore'>
		<view id='list-content' class="list-content">
			<template v-if='dataEmpty'>
				<cu-empty :size="emptySize" :emptyTitle="getEmptyTitle">
                    <slot name="empty"></slot>
				</cu-empty>
			</template>
			<slot v-else>
			</slot>
		</view>
		<view class="list-placeholder-zone" :style='[listPlaceholderStyle]'></view>
		<view class="list-bottom">
			<uni-load-more :status="loadMoreStatus" iconType="snow" :contentText='loadMoreContent'>
			</uni-load-more>
		</view>
	</scroll-view>
</template>

<script>
	const DEFAULT_PAGE_INDEX = 1;
	const DEFAULT_PAGE_SIZE = 20;
	const LOAD_MORE_STATUS = {
		MORE: "MORE",
		LOADING: "LOADING",
		NO_MORE: "NO_MORE"
	}
	import {
		isArray,
		isEmpty
	} from '../../utils/index.js';
	import ComponentMixin from "../../mixins/common-component-mixin.js";
	export default {
		mixins: [ComponentMixin],
		name: "c-list",
		props: {
			value: {
				type: Array,
				default: function() {
					return []
				}
			}, // 外部数据
			ableRefresh: {
				type: Boolean,
				default: true
			}, // 是否允许刷新
			ableLoadMore: {
				type: Boolean,
				default: true
			}, // 是否允许加载更多
			initPageSize: {
				type: Number,
				default: null,
                validator(value) {
					return value > 0
				}
			}, // 接受pageSize, 只允许初始化时传入，后续不接收, 如果为null或者0, 使用默认size
			height: {
				type: Number,
				default: 0
			}, // list 页面高度 单位 px
			emptyTitle: {
				type: String,
				default: "列表暂无数据"
			}, // empty 页面文本
			emptySize: {
				type: String,
				default: "lg",
				validator(value) {
					return ["sm", "base", "lg"].includes(value)
				}
			}, // empty 页面尺寸
		},
		data() {
			return {
				total: 0, // 数据总长
				sources: [], // 数据列表
				placeholderZoneHeight: 0, // placeholder-zone 高度
				loadMoreStatus: LOAD_MORE_STATUS.NO_MORE, // 加载更多状态
				loadMoreContent: {
					contentdown: "上拉加载更多",
					contentrefresh: "更多数据加载中",
					contentnomore: "已经加载到底了"
				}, // 加载更多状态文本
				refreshTrigger: false,
				isRefreshing: false, // 是否刷新中
				pageIndex: DEFAULT_PAGE_INDEX, // pageIndex
				pageSize: DEFAULT_PAGE_SIZE, // pageSize
			};
		},
		watch: {
			height: {
				handler: function(n) {
					this.resetPlacehoderHeight();
				},
				immediate: true
			},
			value: {
				handler: function(n) {
					if (!n || !isArray(n)) {
						this.total = 0;
						this.value = [];
					} else {
						this.sources = n;
					}
				},
				immediate: true
			},
			initPageSize: {
				handler: function(n) {
					if (n && n > 0) {
						this.pageSize = Number(n);
					}
				},
				immediate: true
			},
			sources: {
				handler: function(n) {
					// #ifdef MP-WEIXIN
					this.$nextTick(() => {
						this.resetPlacehoderHeight()
					})
					// #endif
					// #ifndef MP-WEIXIN
					setTimeout(() => {
						this.resetPlacehoderHeight()
					}, 300)
					// #endif
					if (n) { // loadmore 状态变动，loading状态不在其中，loading状态需在加载时手动变更，更新数据列表时响应更新为more和noMore
						this.loadMoreStatus = n.length < this.total ? LOAD_MORE_STATUS.MORE : LOAD_MORE_STATUS.NO_MORE;
					}
				},
				immediate: true
			}
		},
		computed: {
			getEmptyTitle: function() {
				return this.emptyTitle;
			},
			// 列表样式
			listStyle: function() {
				return {
					height: `${this.height ? this.height : uni.getSystemInfoSync().windowHeight}px`
				}
			},
			// placeholder-zone 样式
			listPlaceholderStyle: function() {
				let height = this.placeholderZoneHeight;
				height = height > 0 ? `${height}px` : 0;
				return {
					height: height
				}
			},
			// 数据是否为空
			dataEmpty: function() {
				return isEmpty(this.sources);
			},
			// 是否允许加载更多
			canLoadMore: function() {
				return this.ableLoadMore && (this.loadMoreStatus == LOAD_MORE_STATUS.LOADING || this.loadMoreStatus ==
					LOAD_MORE_STATUS.MORE)
			},
			// 是否加载更多中
			isLoadingMore: function() {
				return this.loadMoreStatus == LOAD_MORE_STATUS.LOADING
			}
		},
		methods: {
			// 重算 placeholder-zone 高度
			resetPlacehoderHeight() {
				const query = uni.createSelectorQuery().in(this);
				query.select("#list-content").boundingClientRect((res) => {
					let listHeight = res ? res.height : 0;
					let cHeight = this.height ? this.height : uni.getSystemInfoSync().windowHeight;
					this.placeholderZoneHeight = cHeight - listHeight;
				})
				query.exec();
			},
			// 下拉刷新
			onPullRefreshing() {
				if (this.ableRefresh) {
					if (this.isLoadingMore || this.isRefreshing) return;
					this.isRefreshing = true;
					if (!this.refreshTrigger) {
						this.refreshTrigger = true;
					}
					this.pageIndex = DEFAULT_PAGE_INDEX;
					this.requestListData();
				} else {
					if (this.refreshTrigger) {
						this.refreshTrigger = false;
					}
				}
			},
			refresh() {
				if (!this.refreshTrigger && !this.isRefreshing) {
					this.refreshTrigger = true;
				}
			},
			// 上拉加载
			onLoadMore() {
				if (this.canLoadMore) {
					if (this.isLoadingMore || this.isRefreshing) return;
					this.loadMoreStatus = LOAD_MORE_STATUS.LOADING;
					this.requestListData();
				}
			},
			// 请求列表数据
			requestListData() {
				let param = {
					pageIndex: this.pageIndex,
					pageSize: this.pageSize
				};
				this.$emit('request', {
					param,
					callback: (promise) => {
						promise.then(data => {
							let rows = data.records;
							let total = data.total;
							if (!rows) {
								rows = data;
								total = data.length;
							}
							this.total = total;
							if (this.pageIndex == DEFAULT_PAGE_INDEX) {
								this.sources = rows;
							} else {
								this.sources = this.sources.concat(rows);
							}
							this.pageIndex++;
						}).catch((err) => {
							this.sources = this.sources; // 用以更新loadmore状态
							if (err) {
								uni.showToast({
									title: err,
									icon: 'none'
								})
							}
						}).finally(() => {
							this.isRefreshing = false;
							if (this.refreshTrigger) {
								this.refreshTrigger = false
							}
							this.$emit("dataChange", {
								isRefreshing: this.isRefreshing,
								isLoadingMore: this.isLoadingMore,
								data: this.sources ? this.sources : [],
								total: this.total,
								pageIndex: this.pageIndex - 1
							})
						});
					}
				})
			}
		},
	}
</script>

<style lang="scss">
	.c-list {
		height: 600px;
	}

	.login-button {
		padding: 0 30rpx;
		height: 60rpx;
		line-height: 60rpx;
		border-radius: 30rpx;
		text-align: center;
		background: $theme-color;
		color: #fff;
	}
</style>